package com.dctp.common.service;

import com.alibaba.fastjson.JSON;
import com.dctp.common.db.DictionaryDb;
import com.dctp.common.utils.DateUtil;
import com.dctp.common.utils.NumberUtil;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

public class CommissionService {
    private static final Logger logger = LoggerFactory.getLogger(CommissionService.class);
    private static final BigDecimal HUNDRED = new BigDecimal("100");
    private static final int       SCALE   = 2;                     // 保留 2 位，随需要调整

    /**
     * 分佣主入口
     *
     *
     */

    private static Map<Integer, String> levelFieldsMap = new HashMap();
    static {
        levelFieldsMap.put(2,"bottom_role_user_id");
        levelFieldsMap.put(3,"middle_role_user_id");
        levelFieldsMap.put(4,"top_role_user_id");
    }

    private static Map<Integer, Record> levelMap = new HashMap<>();
    private static Map<Long,Integer> roleLevelMap = new HashMap<>();

    public static void distributeCommission(Record user, Record order) {

        BigDecimal serviceFee = order.getBigDecimal("service_fee");

        String frServiceRatio = DictionaryDb.getValueByCode("frServiceRatio");
        BigDecimal serviceRatio = NumberUtil.parseBigDecimal(frServiceRatio);
        if (serviceRatio.compareTo(BigDecimal.ZERO) > 0) {
            serviceFee = serviceFee.multiply(BigDecimal.valueOf(100).subtract(serviceRatio))
                    .divide(HUNDRED, SCALE, RoundingMode.HALF_UP);
        }

         // ① 加载角色配置
        List<Record> roleList = Db.find("SELECT id,level,code,fixed_amount,ratio,save_level_fixed_amount,save_level_ratio FROM dctp_role WHERE status=1");
        Map<Integer, Record> levelMapTmp = roleList.stream()
                .collect(Collectors.toMap(r->r.getInt("level"), r->r));
        Map<Long,Integer> roleLevelMapTmp = roleList.stream()
                .collect(Collectors.toMap(r->r.getLong("id"), r->r.getInt("level")));
        levelMap     = Collections.unmodifiableMap(levelMapTmp);
        roleLevelMap = Collections.unmodifiableMap(roleLevelMapTmp);

        //分给自己
        //selfCommission(user,order);
        // 1. 查询用户关系链（parent_id递归向上，查角色code）
        List<Record> chain = getUserChain(user);
        for (Record record : chain) {
            logger.info("分佣人数：{}",JSON.toJSONString(record.toMap()));
        }

        // 2. 级差奖分配
        distributeLevelCommissionV2(chain, serviceFee, order);
        // 3. 同级奖励分配
        distributeSameLevelCommission(chain, serviceFee, order);
    }


    private static void selfCommission(Record user, Record order) {
        Long roleId = user.get("role_id");
        Record roleConfig = Db.findById("dctp_role",roleId);
        if (null == roleConfig) {
            return;
        }
        BigDecimal selfRatio = getRatio(user.getLong("id"),roleId,roleLevelMap.get(roleId));
        selfRatio = selfRatio.divide(HUNDRED, SCALE, RoundingMode.HALF_UP);
        BigDecimal serviceFee = order.getBigDecimal("service_fee");
        BigDecimal frAmount = serviceFee.multiply(selfRatio);
        if (frAmount.compareTo(BigDecimal.ZERO) > 0) {
            saveCommission(user,frAmount,order,1);
            logger.info("分给自己，frAmount：{}，serviceFee:{}",frAmount,serviceFee);
        }
    }

    private static BigDecimal getRatio(Long userId,Long roleId,Integer level) {

        // 当前时间
        LocalDate today = LocalDate.now();

        // 本周周一（根据中国习惯：周一为一周的第一天）
        LocalDate monday = today.with(DayOfWeek.MONDAY);
        LocalDate sunday = today.with(DayOfWeek.SUNDAY);

        // 开始时间：周一 00:00:00
        LocalDateTime weekStart = monday.atStartOfDay();
        // 结束时间：周日 23:59:59.999（精确到毫秒）
        LocalDateTime weekEnd = sunday.atTime(LocalTime.MAX);

        String field = levelFieldsMap.get(level);
        String sql = String.format(
                "SELECT IFNULL(SUM(quantity),0) FROM dctp_order WHERE (%s = ? OR user_id = ?) AND close_time >= ? AND close_time <= ?",
                field
        );
        Integer quantity = Db.queryInt(sql, field, userId, weekStart, weekEnd);
        logger.info("sql :{},userId:{},weekStart:{},weekEnd:{}",sql,userId,weekStart,weekEnd);
        Record config = Db.findFirst(
                "SELECT id, down_limit, up_limit, ratio " +
                        "FROM dctp_commission_config " +
                        "WHERE role_id = ? " +
                        "AND ? >= down_limit " +
                        "AND ? < up_limit " +
                        "ORDER BY down_limit DESC " +
                        "LIMIT 1",
                roleId, quantity, quantity
        );

        if (config != null) {
            logger.info("获取分佣比例 ： userId:{},roleId:{},ratio:{} ",userId,roleId,config.get("ratio"));
            return config.getBigDecimal("ratio");
        } else {
            return BigDecimal.ZERO;
        }
    }



    // 递归查找用户parent链，返回List<Record>，每个Record含id、role_code、parent_id、index
    private static List<Record> getUserChain(Record user) {
        Integer userLevel = roleLevelMap.get(user.getLong("role_id"));
        user.set("level", userLevel);
        List<Record> chain = new ArrayList<>();
        chain.add(user);
        Long current = user.getLong("parent_id");
        while (current != null && current != 0 && chain.size() < 4) {
            Record parent = Db.findFirst(
                "SELECT id, role_id, parent_id, nick_name FROM dctp_user WHERE id=? AND status=1", current);
            if (parent == null) break;

            Integer level = roleLevelMap.get(parent.getLong("role_id"));
            if (level != null && level > 1) {
                parent.set("level", level);
                boolean exists = chain.stream()
                        .anyMatch(r -> r.getLong("role_id").equals(parent.getLong("role_id")));
                if (!exists) chain.add(parent);
            }
            current = parent.getLong("parent_id");
        }
        return chain;
    }


    private static void distributeLevelCommissionV2(List<Record> chain, BigDecimal serviceFee, Record order) {

            //往上找
            BigDecimal level2Commission = BigDecimal.ZERO;
            BigDecimal level3Commission = BigDecimal.ZERO;
            BigDecimal level4Commission = BigDecimal.ZERO;
            LocalDateTime closeTime = order.getLocalDateTime("close_time");
            for (int i = 0;i<chain.size();i++) {
                Record parent = chain.get(i);
                Integer level = parent.getInt("level");

                if (level == 4) {
                    //等于减去运营中心
                    level4Commission = getCommissionSum(closeTime,parent,serviceFee, List.of(level));

                    if (level3Commission.compareTo(BigDecimal.ZERO) > 0) {
                        level4Commission = level4Commission.subtract(level3Commission);
                    }
                    if (level2Commission.compareTo(BigDecimal.ZERO) > 0) {
                        level4Commission = level4Commission.subtract(level2Commission);
                    }
                    logger.info("遇到B端公司,level4Commission:{},level3Commission:{},level2Commission:{},",level4Commission,level3Commission,level2Commission);
                    break;
                }

                if (level == 3) {
                    //运营中心
                    level3Commission = getCommissionSum(closeTime,parent,serviceFee, List.of(level));
                    level3Commission = level3Commission.subtract(level2Commission);
                    logger.info("遇到运营中心,level3Commission:{},level2Commission:{}",level3Commission,level2Commission);
                }

                if (level == 2) {
                    //数据管理员，
                    if (level3Commission.compareTo(BigDecimal.ZERO) == 0 && level4Commission.compareTo(BigDecimal.ZERO) == 0) {
                        level2Commission = getCommissionSum(closeTime,parent,serviceFee, List.of(level));
                        logger.info("遇到数据管理员,level2Commission:{}",level2Commission);
                    }
                }
            }

            if (level2Commission.compareTo(BigDecimal.ZERO) > 0) {
                Record level2User = chain.stream().filter(item->item.getInt("level") == 2).findFirst().orElse(null);
                if (null != level2User) {
                    saveCommission(level2User, level2Commission, order, 1);
                }
            }

            if  (level3Commission.compareTo(BigDecimal.ZERO) > 0) {
                Record level3User = chain.stream().filter(item->item.getInt("level") == 3).findFirst().orElse(null);
                if (null != level3User) {
                    saveCommission(level3User, level3Commission, order, 1);
                }
            }

            if (level4Commission.compareTo(BigDecimal.ZERO) > 0) {
                Record level4User = chain.stream().filter(item->item.getInt("level") == 4).findFirst().orElse(null);
                if (null != level4User) {
                    saveCommission(level4User, level4Commission, order, 1);
                }
            }
    }

    // 获取某些level的分佣金额（优先固定金额，否则比例）
    private static BigDecimal getCommissionSum(LocalDateTime closeTime,Record cuser,BigDecimal serviceFee, List<Integer> levels) {

        //判断是否有分佣资格

        //升级为时间
        LocalDateTime upgradeTime = Db.queryLocalDateTime("select audit_time from dctp_role_recharge where user_id = ? " +
                " and role_id = ? audit_status = 1 order by id desc limit 1 ",cuser.getLong("id"),cuser.getLong("role_id"));
        if (null == upgradeTime) {
            return BigDecimal.ZERO;
        }

        //需要隔天平仓的订单才有分佣
        LocalDate upgradeDate = upgradeTime.toLocalDate();
        LocalDate closeDate = closeTime.toLocalDate();
        if (closeDate.isBefore(upgradeDate) || closeDate.isEqual(upgradeDate)) {
            return BigDecimal.ZERO;
        }

       return levels.stream()
                 .map(lv -> getCommission(cuser,serviceFee, lv))
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private static BigDecimal getCommission(Record cuser,BigDecimal serviceFee, Integer level) {
       
         // issue ⑦ 一并修：roleConf 可能为空
//    Record roleConf = levelMap.get(level);

//    BigDecimal fixedAmount = Optional.ofNullable(roleConf)
//                                     .map(r -> r.getBigDecimal("fixed_amount"))
//                                     .orElse(BigDecimal.ZERO);

//    BigDecimal ratio = Optional.ofNullable(roleConf)
//                               .map(r -> r.getBigDecimal("ratio"))
//                               .orElse(BigDecimal.ZERO);

        BigDecimal ratio = getRatio(cuser.getLong("id"),cuser.getLong("role_id"),level);
//    if (fixedAmount.compareTo(BigDecimal.ZERO) > 0) {
//        return fixedAmount;
//    }
    if (ratio.compareTo(BigDecimal.ZERO) > 0) {
        // issue ⑤：指定 scale + ROUND_HALF_UP
        cuser.set("fr_ratio", ratio);

        return serviceFee.multiply(ratio)
                         .divide(HUNDRED, SCALE, RoundingMode.HALF_UP);
    }
    return BigDecimal.ZERO;
    }

    // 同级奖励分配
   private static void distributeSameLevelCommission(
        List<Record> chain, BigDecimal serviceFee, Record order) {

        for (int i = 0; i < chain.size(); i++) {
            Record cur = chain.get(i);
            Integer level = cur.getInt("level");
            if (level == null || level < 2) continue;       // 只处理 3 级及以上

            Long parentId = cur.getLong("parent_id");
            if (parentId == null || parentId == 0) continue;

            // ⭐ 只查一次上级
            Record parent = Db.findFirst(
                    "SELECT id, role_id FROM dctp_user WHERE id = ? AND status = 1",
                    parentId);
            if (parent == null) continue;

            // 是否同级：比较 role_id 即可
            if (!parent.getInt("role_id").equals(cur.getInt("role_id"))) {
                continue;                                   
            }

            // 计算同级奖
            Record roleConf = levelMap.get(level);
            BigDecimal fixed = Optional.ofNullable(roleConf)
                                    .map(r -> r.getBigDecimal("save_level_fixed_amount"))
                                    .orElse(BigDecimal.ZERO);

            BigDecimal ratio = Optional.ofNullable(roleConf)
                                    .map(r -> r.getBigDecimal("save_level_ratio"))
                                    .orElse(BigDecimal.ZERO);


            BigDecimal amt = BigDecimal.ZERO;
            if (fixed.compareTo(BigDecimal.ZERO) > 0) {
                amt = fixed;
            } else if (ratio.compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal frRatio = getRatio(parentId,parent.getLong("role_id"),level);
                frRatio = frRatio.divide(HUNDRED, SCALE, RoundingMode.HALF_UP);
                amt = serviceFee.multiply(ratio).multiply(frRatio)
                                .divide(HUNDRED, SCALE, RoundingMode.HALF_UP);

                logger.info("统计奖励。parent:{},ratio:{},fr_ratio:{},amt:{}", parentId,ratio,frRatio,amt);
                amt = amt.setScale(2, RoundingMode.HALF_UP);
                parent.set("fr_ratio", ratio); // 保存比例到订单
            }
            if (amt.compareTo(BigDecimal.ZERO) > 0) {
                saveCommission(parent, amt, order, 2);
            }
        }
    }


    // 保存分佣记录
    private static void saveCommission(Record parent, BigDecimal amount, Record order,Integer frType) {

        LocalDateTime now = DateUtil.now();
        Long orderId = order.getLong("id");
        Long userId = parent.getLong("id");
        Long id = Db.queryLong("select id from dctp_commission_record where user_id = ? and order_id = ? and fr_type = ? ", userId, orderId,frType);
        if (null == id) {
            Record rec = new Record()
                    .set("user_id", userId)
                    .set("order_id", orderId)
                    .set("order_user_id", order.getLong("user_id"))
                    .set("create_time", now)
                    .set("update_time", now)
                    .set("fr_amount", amount)
                    .set("remark", frType == 1 ? "级差奖" : "同级奖")
                    .set("fr_type", frType)
                    .set("count_status", 0)//需要手动结算
                    .set("service_fee", order.getBigDecimal("service_fee"))
                    .set("role_id", parent.getLong("role_id")) // 保存角色ID
                    .set("stat_day", DateUtil.format(now, "yyyy-MM-dd")) // 保存统计日期
                    .set("ratio", parent.getBigDecimal("fr_ratio")); // 保存比例


            Record p = Db.findById("dctp_user", userId);
            Long parentId = p.getLong("parent_id");
            Long bottomRoleUserId = p.getLong("bottom_role_user_id");
            Long middleRoleUserId = p.getLong("middle_role_user_id");
            Long topRoleUserId = p.getLong("top_role_user_id");
            rec.set("parent_id", parentId)
                    .set("bottom_role_user_id", bottomRoleUserId)
                    .set("middle_role_user_id", middleRoleUserId)
                    .set("top_role_user_id", topRoleUserId);

            Db.save("dctp_commission_record", rec);
        }
    }
}
